package statistics;

import java.util.Random;

/**
 * This class represents an Histogram Distribution.
 */

public class Histogram extends DiscreteDistribution {

  private int[] histogramarray = new int[22];
  private double[] cumulativeprob = new double[23];
  private DiscreteDistribution distr;
  private int total;
  private double[] more20days = new double[2];
  
  /**
   * Constructs an Histogram Distribution. You must also
   * specify the random seed that will be used to realize random variables with this
   * distribution.
   * @param random the randomseed.
   */

  public Histogram(int[] histogramarray, double[] more20days,Random random) {
    this.histogramarray = histogramarray;
    this.random = random;
    this.more20days = more20days;
    total = 0;
    for (int i = 0; i < 22; i++) {
       total = total + histogramarray[i];
    } //for
    cumulativeprob[0] = 0;
    cumulativeprob[1] = ((double)histogramarray[0])/total;
    for (int i = 2; i < 23; i++) {
       cumulativeprob[i] = ((double)histogramarray[i-1])/total + cumulativeprob[i-1];
    } //for

    double variationCoefficient = 0;
    double a = 0;
    if(more20days[1] != 0) {
        variationCoefficient = more20days[1] / Math.pow(more20days[0],2);
        a = variationCoefficient - 1.0/more20days[0];

   //    if((more20days[1] == 0) && (more20days[0] == 0)) {
   //       System.out.println("variationCoefficient: "+variationCoefficient);
   //       System.out.println("a: "+a);
   //    }

       if(a == 0 || a == Double.NaN) {
         distr = new PoissonDistribution(more20days[0],random);
       }
       if(a >= 1) {
         distr = new MixGeometricDistribution(more20days[0],a,random);
       }
       if(a < 0) {
         distr = new MixBinomialDistribution(more20days[0],a,random);
       }
       if((0 < a) && (a < 1)) {
         distr = new MixNegBinomialDistribution(more20days[0],a,random);
       }
   }//end if
}

  /**
   * Returns the expectation of a random variable with a Histogram distribution.
   */

  public double expectation() {
     double sum = 0;
     double aantal = 0;
     for(int i = 0; i < 21; i++) {
        sum = sum + i * histogramarray[i];
        aantal = aantal + histogramarray[i];
     }
     sum = sum + histogramarray[21]*(20 + more20days[0]);
     aantal = aantal + histogramarray[21];
     return sum/aantal;
  }

  public double variance() {
     double exp = expectation();
     double sum = 0;
     double aantal = 0;
     for(int i = 0; i < 21; i++) {
        sum = sum + histogramarray[i]*(i-exp)*(i-exp);
        aantal = aantal + histogramarray[i];
     }
     sum = sum + histogramarray[21]*(20 + more20days[0] - exp)*(20 + more20days[0]-exp);
     aantal = aantal + histogramarray[21];
     return sum/aantal;
  }

  public double probabilityFunction(int k) {
    return cumulativeprob[k] - (k > 0 ? cumulativeprob[k-1] : 0);
  }

  /**
   * Returns a realization of a random variable with a Histogram distribution.
   */

 public double nextRandom() {
    double u = random.nextDouble();
    int k = 0;
    double m;
    for(k = 0; cumulativeprob[k+1] <= u;k++);
    if (k < 21) {
       m = ((double) k * 2);
       return m;
    } //if
    else {
       if(more20days[1] == 0) {
          m = more20days[0];
       }
       else {
          m = distr.nextRandom();
       }
       return (m + 20);
    }
  }


  /**
   * A discrete distribution must implement nextFA.
   */

  public double nextFA() {
     return -1;
  }

} 
